package com.pengiummer.blogpublisher.popup.actions;

import java.io.IOException;
import java.net.URL;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

import com.google.gdata.client.Query;
import com.google.gdata.client.blogger.BloggerService;
import com.google.gdata.data.DateTime;
import com.google.gdata.data.Entry;
import com.google.gdata.data.Feed;
import com.google.gdata.data.HtmlTextConstruct;
import com.google.gdata.data.Person;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.TextContent;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;
import com.pengiummer.blogpublisher.popup.services.BlogPublishService;
import com.pengiummer.blogpublisher.popup.services.Blogger;

/**
 * Demonstrates how to use the Google Data API's Java client library to
 * interface with the Blogger service. There are examples for the following
 * operations:
 * 
 * <ol>
 * <li>Retrieving the list of all the user's blogs</li>
 * <li>Retrieving all posts on a single blog</li>
 * <li>Performing a date-range query for posts on a blog</li>
 * <li>Creating draft posts and publishing posts</li>
 * <li>Updating posts</li>
 * <li>Retrieving comments</li>
 * <li>Deleting posts</li>
 * </ol>
 * 
 * 
 */
public class BlogClient {

	private static final String METAFEED_URL = "http://www.blogger.com/feeds/default/blogs";

	private static final String FEED_URI_BASE = "http://www.blogger.com/feeds";
	private static final String POSTS_FEED_URI_SUFFIX = "/posts/default";
	private static final String COMMENTS_FEED_URI_SUFFIX = "/comments/default";

	private BloggerService bloggerService;
	private String blogId;
	private String feedUri;
	private URL feedUrl;

	/**
	 * Utility classes should not have a public or default constructor.
	 */
	public BlogClient(String blogName) {
		bloggerService = new BloggerService(blogName);
	}

	public void initConnection() throws ServiceException, IOException {
		blogId = getBlogId();
		feedUri = FEED_URI_BASE + "/" + blogId;
		feedUrl = new URL(feedUri + POSTS_FEED_URI_SUFFIX);
	}

	public void authenticate(String userName, String password)
			throws AuthenticationException {
		bloggerService.setUserCredentials(userName, password);

	}

	public List<Post> getAllPosts() throws IOException, ServiceException {
		Feed resultFeed = bloggerService.getFeed(feedUrl, Feed.class);

		List<Post> posts = new ArrayList<Post>();
		for (int i = 0; i < resultFeed.getEntries().size(); i++) {
			Entry entry = resultFeed.getEntries().get(i);
			int contentType = entry.getContent().getType();
			Post post = convertPost(entry);

			posts.add(post);
		}
		return posts;
	}

	private Post convertPost(Entry entry) {
		Post post = new Post(entry.getId().split("post-")[1], entry.getTitle().getPlainText(),
				entry.getTextContent().getContent().getPlainText(), new Timestamp(
						entry.getPublished().getValue()));
		if(entry.getTextContent().getContent() instanceof HtmlTextConstruct){
			post.setHtmlContent(((HtmlTextConstruct)entry.getTextContent().getContent()).getHtml());
		}
		return post;
	}

	/**
	 * Parses the metafeed to get the blog ID for the authenticated user's default
	 * blog.
	 * 
	 * @return A String representation of the blog's ID.
	 * @throws ServiceException
	 *           If the service is unable to handle the request.
	 * @throws IOException
	 *           If the URL is malformed.
	 */
	public String getBlogId() throws ServiceException, IOException {
		// Get the metafeed
		final URL feedUrl = new URL(METAFEED_URL);
		Feed resultFeed = bloggerService.getFeed(feedUrl, Feed.class);

		// If the user has a blog then return the id (which comes after 'blog-')
		if (resultFeed.getEntries().size() > 0) {
			Entry entry = resultFeed.getEntries().get(0);
			return entry.getId().split("blog-")[1];
		}
		throw new IOException("User has no blogs!");
	}

	/**
	 * Prints a list of all the user's blogs.
	 * 
	 * @throws ServiceException
	 *           If the service is unable to handle the request.
	 * @throws IOException
	 *           If the URL is malformed.
	 */
	public void printUserBlogs() throws ServiceException, IOException {

		// Request the feed
		final URL feedUrl = new URL(METAFEED_URL);
		Feed resultFeed = bloggerService.getFeed(feedUrl, Feed.class);

		// Print the results
		System.out.println(resultFeed.getTitle().getPlainText());
		for (int i = 0; i < resultFeed.getEntries().size(); i++) {
			Entry entry = resultFeed.getEntries().get(i);
			System.out.println("\t" + entry.getTitle().getPlainText());
		}
		System.out.println();
	}

	/**
	 * Creates a new post on a blog. The new post can be stored as a draft or
	 * published based on the value of the isDraft paramter. The method creates an
	 * Entry for the new post using the title, content, authorName and isDraft
	 * parameters. Then it uses the given GoogleService to insert the new post. If
	 * the insertion is successful, the added post will be returned.
	 * 
	 * @param title
	 *          Text for the title of the post to create.
	 * @param content
	 *          Text for the content of the post to create.
	 * @param authorName
	 *          Display name of the author of the post.
	 * @param userName
	 *          username of the author of the post.
	 * @param isDraft
	 *          True to save the post as a draft, False to publish the post.
	 * @return An Entry containing the newly-created post.
	 * @throws ServiceException
	 *           If the service is unable to handle the request.
	 * @throws IOException
	 *           If the URL is malformed.
	 */
	public Entry createPost(String title, String content, String authorName,
			String userName, Boolean isDraft) throws ServiceException, IOException {
		// Create the entry to insert
		Entry myEntry = new Entry();
		myEntry.setTitle(new PlainTextConstruct(title));
		myEntry.setContent(new PlainTextConstruct(content));
		Person author = new Person(authorName, null, userName);
		myEntry.getAuthors().add(author);
		myEntry.setDraft(isDraft);

		// Ask the service to insert the new entry
		URL postUrl = new URL(feedUri + POSTS_FEED_URI_SUFFIX);
		//bloggerService.update(myEntry.getEditLink().getHref(), myEntry);
		Entry newEntry = bloggerService.insert(postUrl, myEntry);
		System.out.println(postUrl);
		System.out.println(newEntry.getId());
		System.out.println(newEntry.getEditLink().getHref());
		return newEntry;
	}

	public Post publishPost(String id, String title, String content, String authorName,
			String userName) throws ServiceException, IOException {
		// Create the entry to insert
		Entry myEntry = new Entry();
		myEntry.setTitle(new PlainTextConstruct(title));
		myEntry.setContent(new PlainTextConstruct(content));
		Person author = new Person(authorName, null, userName);
		myEntry.getAuthors().add(author);

		Entry newEntry;
		if(id!=null&& !id.trim().equals("")){
			URL postUrl = new URL(feedUri + POSTS_FEED_URI_SUFFIX+"/"+id);
			newEntry = bloggerService.update(postUrl, myEntry);
		}else{
			URL postUrl = new URL(feedUri + POSTS_FEED_URI_SUFFIX);
			newEntry = bloggerService.insert(postUrl, myEntry);
		}
		return convertPost(newEntry);
	}

	/**
	 * Displays the titles of all the posts in a blog. First it requests the posts
	 * feed for the blogs and then is prints the results.
	 * 
	 * @throws ServiceException
	 *           If the service is unable to handle the request.
	 * @throws IOException
	 *           If the URL is malformed.
	 */
	public void printAllPosts() throws ServiceException, IOException {
		// Request the feed
		URL feedUrl = new URL(feedUri + POSTS_FEED_URI_SUFFIX);
		Feed resultFeed = bloggerService.getFeed(feedUrl, Feed.class);

		// Print the results
		System.out.println(resultFeed.getTitle().getPlainText());
		for (int i = 0; i < resultFeed.getEntries().size(); i++) {
			Entry entry = resultFeed.getEntries().get(i);
			System.out.println("\t" + entry.getTitle().getPlainText());
			System.out.println(entry.getTextContent().getContent().getPlainText());
		}
		System.out.println();
	}

	/**
	 * Displays the title and modification time for any posts that have been
	 * created or updated in the period between the startTime and endTime
	 * parameters. The method creates the query, submits it to the GoogleService,
	 * then displays the results.
	 * 
	 * Note that while the startTime is inclusive, the endTime is exclusive, so
	 * specifying an endTime of '2007-7-1' will include those posts up until
	 * 2007-6-30 11:59:59PM.
	 * 
	 * @param startTime
	 *          DateTime object specifying the beginning of the search period
	 *          (inclusive).
	 * @param endTime
	 *          DateTime object specifying the end of the search period
	 *          (exclusive).
	 * @throws ServiceException
	 *           If the service is unable to handle the request.
	 * @throws IOException
	 *           If the URL is malformed.
	 */
	public void printDateRangeQueryResults(DateTime startTime, DateTime endTime)
			throws ServiceException, IOException {
		// Create query and submit a request
		URL feedUrl = new URL(feedUri + POSTS_FEED_URI_SUFFIX);
		Query myQuery = new Query(feedUrl);
		myQuery.setUpdatedMin(startTime);
		myQuery.setUpdatedMax(endTime);
		Feed resultFeed = bloggerService.query(myQuery, Feed.class);

		// Print the results
		System.out.println(resultFeed.getTitle().getPlainText() + " posts between "
				+ startTime + " and " + endTime);
		for (int i = 0; i < resultFeed.getEntries().size(); i++) {
			Entry entry = resultFeed.getEntries().get(i);
			System.out.println("\t" + entry.getTitle().getPlainText());
			System.out.println("\t" + entry.getUpdated().toStringRfc822());
		}
		System.out.println();
	}

	/**
	 * Updates the title of the given post. The Entry object is updated with the
	 * new title, then a request is sent to the GoogleService. If the insertion is
	 * successful, the updated post will be returned.
	 * 
	 * Note that other characteristics of the post can also be modified by
	 * updating the values of the entry object before submitting the request.
	 * 
	 * @param entryToUpdate
	 *          An Entry containing the post to update.
	 * @param newTitle
	 *          Text to use for the post's new title.
	 * @return An Entry containing the newly-updated post.
	 * @throws ServiceException
	 *           If the service is unable to handle the request.
	 * @throws IOException
	 *           If the URL is malformed.
	 */
	public Entry updatePostTitle(Entry entryToUpdate, String newTitle)
			throws ServiceException, IOException {
		entryToUpdate.setTitle(new PlainTextConstruct(newTitle));
		URL editUrl = new URL(entryToUpdate.getEditLink().getHref());
		return bloggerService.update(editUrl, entryToUpdate);
	}

	/**
	 * Adds a comment to the specified post. First the comment feed's URI is built
	 * using the given post ID. Then an Entry is created for the comment and
	 * submitted to the GoogleService.
	 * 
	 * NOTE: This functionality is not officially supported yet.
	 * 
	 * @param postId
	 *          The ID of the post to comment on.
	 * @param commentText
	 *          Text to store in the comment.
	 * @return An entry containing the newly-created comment.
	 * @throws ServiceException
	 *           If the service is unable to handle the request.
	 * @throws IOException
	 *           If the URL is malformed.
	 */
	public Entry createComment(String postId, String commentText)
			throws ServiceException, IOException {
		// Build the comment feed URI
		String commentsFeedUri = feedUri + "/" + postId + COMMENTS_FEED_URI_SUFFIX;
		URL feedUrl = new URL(commentsFeedUri);

		// Create a new entry for the comment and submit it to the GoogleService
		Entry myEntry = new Entry();
		myEntry.setContent(new PlainTextConstruct(commentText));
		return bloggerService.insert(feedUrl, myEntry);
	}

	/**
	 * Displays all the comments for the given post. First the comment feed's URI
	 * is built using the given post ID. Then the method requests the comments
	 * feed and displays the results.
	 * 
	 * @param postId
	 *          The ID of the post to view comments on.
	 * @throws ServiceException
	 *           If the service is unable to handle the request.
	 * @throws IOException
	 *           If there is an error communicating with the server.
	 */
	public void printAllComments(String postId) throws ServiceException,
			IOException {
		// Build comment feed URI and request comments on the specified post
		String commentsFeedUri = feedUri + "/" + postId + COMMENTS_FEED_URI_SUFFIX;
		URL feedUrl = new URL(commentsFeedUri);
		Feed resultFeed = bloggerService.getFeed(feedUrl, Feed.class);

		// Display the results
		System.out.println(resultFeed.getTitle().getPlainText());
		for (int i = 0; i < resultFeed.getEntries().size(); i++) {
			Entry entry = resultFeed.getEntries().get(i);
			System.out.println("\t"
					+ ((TextContent) entry.getContent()).getContent().getPlainText());
			System.out.println("\t" + entry.getUpdated().toStringRfc822());
		}
		System.out.println();
	}

	/**
	 * Removes the comment specified by the given editLinkHref.
	 * 
	 * @param editLinkHref
	 *          The URI given for editing the comment.
	 * @throws ServiceException
	 *           If the service is unable to handle the request.
	 * @throws IOException
	 *           If there is an error communicating with the server.
	 */
	public void deleteComment(String editLinkHref) throws ServiceException,
			IOException {
		URL deleteUrl = new URL(editLinkHref);
		bloggerService.delete(deleteUrl);
	}

	/**
	 * Removes the post specified by the given editLinkHref.
	 * 
	 * @param editLinkHref
	 *          The URI given for editing the post.
	 * @throws ServiceException
	 *           If the service is unable to handle the request.
	 * @throws IOException
	 *           If there is an error communicating with the server.
	 */
	public void deletePost(String editLinkHref) throws ServiceException,
			IOException {
		URL deleteUrl = new URL(editLinkHref);
		bloggerService.delete(deleteUrl);
	}

	/**
	 * Runs through all the examples using the given GoogleService instance.
	 * 
	 * @param userName
	 *          username of user to authenticate (e.g. jdoe@gmail.com).
	 * @param userPassword
	 *          password to use for authentication.
	 * @throws ServiceException
	 *           If the service is unable to handle the request.
	 * @throws IOException
	 *           If there is an error communicating with the server.
	 */
	public void run(String userName, String userPassword)
			throws ServiceException, IOException {
		// Authenticate using ClientLogin
		bloggerService.setUserCredentials(userName, userPassword);

		// Get the blog ID from the metatfeed.
		String blogId = getBlogId();
		feedUri = FEED_URI_BASE + "/" + blogId;

		// Demonstrate retrieving a list of the user's blogs.
		printUserBlogs();

		// Demonstrate how to create a draft post.
		Entry draftPost = createPost("Snorkling in Aruba",
				"<p>We had so much fun snorkling in Aruba<p>", "Post author", userName,
				true);
		System.out.println("Successfully created draft post: "
				+ draftPost.getTitle().getPlainText());

		// Demonstrate how to publish a public post.
		Entry publicPost = createPost("Back from vacation",
				"<p>I didn't want to leave Aruba, but I ran out of money :(<p>",
				"Post author", userName, false);
		System.out.println("Successfully created public post: "
				+ publicPost.getTitle().getPlainText());

		// Demonstrate various feed queries.
		printAllPosts();
		printDateRangeQueryResults(DateTime.parseDate("2007-04-04"), DateTime
				.parseDate("2007-04-06"));

		// Demonstrate two ways of updating posts.
		draftPost.setTitle(new PlainTextConstruct("Swimming with the fish"));
		draftPost.update();
		System.out.println("Post's new title is \""
				+ draftPost.getTitle().getPlainText() + "\".\n");
		publicPost = updatePostTitle(publicPost, "The party's over");
		System.out.println("Post's new title is \""
				+ publicPost.getTitle().getPlainText() + "\".\n");

		// Demonstrate how to add a comment on a post
		// Get the post ID and build the comments feed URI for the specified post
		System.out.println("Creating comment");
		String selfLinkHref = publicPost.getSelfLink().getHref();
		String[] tokens = selfLinkHref.split("/");
		String postId = tokens[tokens.length - 1];
		Entry comment = createComment(postId, "Did you see any sharks?");

		// Demonstrate how to retrieve the comments for a post
		printAllComments(postId);

		// Demonstrate how to delete a comment from a post
		System.out.println("Deleting comment");
		deleteComment(comment.getEditLink().getHref());

		// Demonstrate two ways of deleting posts.
		System.out.println("Deleting draft post");
		draftPost.delete();
		System.out.println("Deleting published post");
		deletePost(publicPost.getEditLink().getHref());
	}

	/**
	 * Uses the command line arguments to authenticate the GoogleService and build
	 * the basic feed URI, then invokes all the other methods to demonstrate how
	 * to interface with the Blogger service.
	 * 
	 * @param args
	 *          See the usage method.
	 */
	public static void main(String[] args) {

		// Set username, password and feed URI from command-line arguments.
		// SimpleCommandLineParser parser = new SimpleCommandLineParser(args);
		BlogPublishService publishService = new BlogPublishService();
		Blogger blogger = publishService.loadBlogger();
		String userName = blogger.getAccountName();
		String userPassword = blogger.getPassword();

		BlogClient client = new BlogClient(blogger.getBlogName());

		try {
			client.run(userName, userPassword);
		} catch (ServiceException se) {
			se.printStackTrace();
		} catch (IOException ioe) {
			ioe.printStackTrace();
		}
	}

	/**
	 * Prints the command line usage of this sample application.
	 */
	private static void usage() {
		System.out.println("Usage: BloggerClient --username <username>"
				+ " --password <password>");
		System.out.println("\nA simple application that creates, queries,\n"
				+ "updates and deletes posts and comments on the\n"
				+ "specified blog using the provided username and\n"
				+ "password for authentication.");
	}
}
